import 'package:math_keyboard/src/foundation/node.dart';
import 'package:math_keyboard/src/foundation/extended_nodes.dart';
import 'package:math_keyboard/src/foundation/structure_validator.dart';

/// Result of an auto-fix operation.
class AutoFixResult {
  /// Creates an [AutoFixResult].
  const AutoFixResult({
    required this.success,
    required this.message,
    this.fixedErrors = const [],
    this.remainingErrors = const [],
  });

  /// Whether the auto-fix was successful.
  final bool success;

  /// Description of what was fixed or why it failed.
  final String message;

  /// List of errors that were successfully fixed.
  final List<ValidationError> fixedErrors;

  /// List of errors that could not be fixed automatically.
  final List<ValidationError> remainingErrors;

  @override
  String toString() => 'AutoFixResult: $message';
}

/// Automatic fixer for common mathematical structure issues.
class AutoFixer {
  /// Fixes incomplete structures in the document.
  static AutoFixResult fixIncompleteStructures(TeXNode root) {
    final errors = StructureValidator.validateDocument(root);
    final fixedErrors = <ValidationError>[];
    final remainingErrors = <ValidationError>[];

    for (final error in errors) {
      final fixResult = _fixSingleError(error);
      if (fixResult) {
        fixedErrors.add(error);
      } else {
        remainingErrors.add(error);
      }
    }

    return AutoFixResult(
      success: fixedErrors.isNotEmpty,
      message: fixedErrors.isNotEmpty
          ? 'Fixed ${fixedErrors.length} errors, ${remainingErrors.length} remaining'
          : 'No errors could be fixed automatically',
      fixedErrors: fixedErrors,
      remainingErrors: remainingErrors,
    );
  }

  /// Fills empty placeholders with default values.
  static AutoFixResult fillEmptyPlaceholders(TeXNode root, String defaultValue) {
    int filledCount = 0;
    
    void fillPlaceholdersRecursive(TeXNode node) {
      for (final child in node.children) {
        if (child is EditableBox && child.isEmpty) {
          child.content.addTeX(TeXLeaf(defaultValue));
          filledCount++;
        } else if (child is TeXFunction) {
          for (final argNode in child.argNodes) {
            fillPlaceholdersRecursive(argNode);
          }
        }
      }
    }

    fillPlaceholdersRecursive(root);

    return AutoFixResult(
      success: filledCount > 0,
      message: filledCount > 0
          ? 'Filled $filledCount empty placeholders with "$defaultValue"'
          : 'No empty placeholders found',
    );
  }

  /// Fixes empty function arguments by adding placeholders.
  static AutoFixResult fixEmptyFunctionArguments(TeXNode root) {
    int fixedCount = 0;

    void fixEmptyArgsRecursive(TeXNode node) {
      for (final child in node.children) {
        if (child is TeXFunction) {
          // Fix empty arguments
          for (final argNode in child.argNodes) {
            if (argNode.children.isEmpty) {
              argNode.addTeX(EditableBox(placeholder: '?'));
              fixedCount++;
            }
            // Recursively fix nested functions
            fixEmptyArgsRecursive(argNode);
          }
        }
      }
    }

    fixEmptyArgsRecursive(root);

    return AutoFixResult(
      success: fixedCount > 0,
      message: fixedCount > 0
          ? 'Added placeholders to $fixedCount empty function arguments'
          : 'No empty function arguments found',
    );
  }

  /// Fixes matrix structures by ensuring all cells exist.
  static AutoFixResult fixMatrixStructures(TeXNode root) {
    int fixedCount = 0;

    void fixMatricesRecursive(TeXNode node) {
      for (final child in node.children) {
        if (child is TeXMatrix) {
          // Ensure all matrix cells exist and have content
          for (int row = 0; row < child.rows; row++) {
            for (int col = 0; col < child.columns; col++) {
              try {
                final cell = child.getCell(row, col);
                if (cell.children.isEmpty) {
                  cell.addTeX(EditableBox(placeholder: '0'));
                  fixedCount++;
                }
              } catch (e) {
                // Cell doesn't exist, create it
                child.setCell(row, col, TeXNode(child));
                child.getCell(row, col).addTeX(EditableBox(placeholder: '0'));
                fixedCount++;
              }
            }
          }
        } else if (child is TeXFunction) {
          for (final argNode in child.argNodes) {
            fixMatricesRecursive(argNode);
          }
        }
      }
    }

    fixMatricesRecursive(root);

    return AutoFixResult(
      success: fixedCount > 0,
      message: fixedCount > 0
          ? 'Fixed $fixedCount matrix cells'
          : 'No matrix issues found',
    );
  }

  /// Fixes limit expressions by adding missing components.
  static AutoFixResult fixLimitExpressions(TeXNode root) {
    int fixedCount = 0;

    void fixLimitExpressionsRecursive(TeXNode node) {
      for (final child in node.children) {
        if (child is TeXLimitExpression) {
          // Fix missing limits based on expression type
          switch (child.expression) {
            case r'\int':
              if (child.hasLowerLimit && child.lowerLimit!.children.isEmpty) {
                child.lowerLimit!.addTeX(EditableBox(placeholder: 'a'));
                fixedCount++;
              }
              if (child.hasUpperLimit && child.upperLimit!.children.isEmpty) {
                child.upperLimit!.addTeX(EditableBox(placeholder: 'b'));
                fixedCount++;
              }
              if (child.hasBody && child.bodyNode != null && child.bodyNode!.children.isEmpty) {
                child.bodyNode!.addTeX(EditableBox(placeholder: 'f(x)dx'));
                fixedCount++;
              }
              break;
            case r'\sum':
            case r'\prod':
              if (child.hasLowerLimit && child.lowerLimit!.children.isEmpty) {
                child.lowerLimit!.addTeX(EditableBox(placeholder: 'i=1'));
                fixedCount++;
              }
              if (child.hasUpperLimit && child.upperLimit!.children.isEmpty) {
                child.upperLimit!.addTeX(EditableBox(placeholder: 'n'));
                fixedCount++;
              }
              break;
            case r'\lim':
              if (child.hasLowerLimit && child.lowerLimit!.children.isEmpty) {
                child.lowerLimit!.addTeX(EditableBox(placeholder: 'x→0'));
                fixedCount++;
              }
              break;
          }
        } else if (child is TeXFunction) {
          for (final argNode in child.argNodes) {
            fixLimitExpressionsRecursive(argNode);
          }
        }
      }
    }

    fixLimitExpressionsRecursive(root);

    return AutoFixResult(
      success: fixedCount > 0,
      message: fixedCount > 0
          ? 'Fixed $fixedCount limit expression components'
          : 'No limit expression issues found',
    );
  }

  /// Fixes subscript/superscript structures.
  // static AutoFixResult fixSubscriptSuperscript(TeXNode root) {
  //   int fixedCount = 0;
  //
  //   void fixSubscriptSuperscriptRecursive(TeXNode node) {
  //     for (final child in node.children) {
  //       if (child is TeXSubscriptSuperscript) {
  //         // Fix empty base
  //         if (child.baseNode.children.isEmpty) {
  //           child.baseNode.addTeX(EditableBox(placeholder: 'x'));
  //           fixedCount++;
  //         }
  //
  //         // Fix empty subscript
  //         if (child.hasSubscript && child.subscriptNode!.children.isEmpty) {
  //           child.subscriptNode!.addTeX(EditableBox(placeholder: 'i'));
  //           fixedCount++;
  //         }
  //
  //         // Fix empty superscript
  //         if (child.hasSuperscript && child.superscriptNode!.children.isEmpty) {
  //           child.superscriptNode!.addTeX(EditableBox(placeholder: '2'));
  //           fixedCount++;
  //         }
  //       } else if (child is TeXFunction) {
  //         for (final argNode in child.argNodes) {
  //           fixSubscriptSuperscriptRecursive(argNode);
  //         }
  //       }
  //     }
  //   }
  //
  //   fixSubscriptSuperscriptRecursive(root);
  //
  //   return AutoFixResult(
  //     success: fixedCount > 0,
  //     message: fixedCount > 0
  //         ? 'Fixed $fixedCount subscript/superscript components'
  //         : 'No subscript/superscript issues found',
  //   );
  // }

  /// Fixes parent-child relationships in the document.
  static AutoFixResult fixParentChildRelationships(TeXNode root) {
    int fixedCount = 0;

    void fixRelationshipsRecursive(TeXNode node, TeXFunction? expectedParent) {
      // Fix parent reference if incorrect
      if (expectedParent != null && node.parent != expectedParent) {
        node.parent = expectedParent;
        fixedCount++;
      }

      for (final child in node.children) {
        if (child is TeXFunction) {
          // Fix parent references for function arguments
          for (final argNode in child.argNodes) {
            fixRelationshipsRecursive(argNode, child);
          }
        }
      }
    }

    fixRelationshipsRecursive(root, null);

    return AutoFixResult(
      success: fixedCount > 0,
      message: fixedCount > 0
          ? 'Fixed $fixedCount parent-child relationships'
          : 'No parent-child relationship issues found',
    );
  }

  /// Performs a comprehensive auto-fix of the document.
  static AutoFixResult fixAll(TeXNode root) {
    final results = <AutoFixResult>[];
    
    // Fix in order of importance
    results.add(fixParentChildRelationships(root));
    results.add(fixEmptyFunctionArguments(root));
    results.add(fixMatrixStructures(root));
    results.add(fixLimitExpressions(root));
    // results.add(fixSubscriptSuperscript(root));
    
    final totalFixed = results.fold<int>(0, (sum, result) => 
        sum + result.fixedErrors.length);
    final totalRemaining = results.fold<int>(0, (sum, result) => 
        sum + result.remainingErrors.length);

    return AutoFixResult(
      success: totalFixed > 0,
      message: 'Auto-fix complete: $totalFixed issues fixed, $totalRemaining remaining',
      fixedErrors: results.expand((r) => r.fixedErrors).toList(),
      remainingErrors: results.expand((r) => r.remainingErrors).toList(),
    );
  }

  /// Attempts to fix a single validation error.
  static bool _fixSingleError(ValidationError error) {
    switch (error.type) {
      case ValidationErrorType.emptyFunction:
        if (error.node != null) {
          error.node!.addTeX(EditableBox(placeholder: '?'));
          return true;
        }
        break;
      case ValidationErrorType.emptyMatrix:
        // This would be handled by fixMatrixStructures
        return false;
      case ValidationErrorType.incompleteLimitExpression:
        // This would be handled by fixLimitExpressions
        return false;
      case ValidationErrorType.missingSubscriptSuperscript:
        // This would be handled by fixSubscriptSuperscript
        return false;
      case ValidationErrorType.invalidStructure:
      case ValidationErrorType.invalidMatrixDimensions:
      case ValidationErrorType.circularReference:
        // These require more complex fixes
        return false;
    }
    return false;
  }

  /// Creates default content for different types of mathematical structures.
  static Map<String, String> get defaultPlaceholders => {
    'variable': 'x',
    'number': '0',
    'index': 'i',
    'limit_lower': 'a',
    'limit_upper': 'b',
    'sum_lower': 'i=1',
    'sum_upper': 'n',
    'integral_body': 'f(x)dx',
    'limit_approach': 'x→0',
    'matrix_element': '0',
    'exponent': '2',
    'base': 'x',
  };

  /// Gets an appropriate placeholder for a given context.
  static String getContextualPlaceholder(String context) {
    return defaultPlaceholders[context] ?? '?';
  }
}